package cn.lg.soar.common.util.jackson;

import cn.lg.soar.common.util.jackson.deserializer.*;
import cn.lg.soar.common.util.jackson.serializer.*;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Jackson 工具
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class JacksonUtil {

    public static volatile ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = buildMapper();
    }

    private JacksonUtil() {}

    public static ObjectMapper buildMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 序列化所有字段和geter seter，只序列化 public 修饰的
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
        // 序列化时忽略 null 的属性
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // 如果是空对象的时候,不抛异常
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 开启日期序列化为时间戳的功能
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
        // 反序列化的时候如果多了其他属性,不抛出异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        SimpleModule simpleModule = new SimpleModule();
        // 添加自定义序列化器
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Enum.class, EnumSerializer.instance);
        simpleModule.addSerializer(LocalDateTime.class, new SLocalDateTimeSerializer());
        simpleModule.addSerializer(LocalDate.class, new SLocalDateSerializer());
        simpleModule.addSerializer(LocalTime.class, new SLocalTimeSerializer());
        simpleModule.addSerializer(Date.class, new SDateSerializer());

        // 添加自定义反序列化器
        simpleModule.addDeserializer(Enum.class, EnumDeserializer.instance);
        simpleModule.addDeserializer(LocalDateTime.class, new SLocalDateTimeDeserializer());
        simpleModule.addDeserializer(LocalDate.class, new SLocalDateDeserializer());
        simpleModule.addDeserializer(LocalTime.class, new SLocalTimeDeserializer());
        simpleModule.addDeserializer(Date.class, new SDateDeserializer());

        objectMapper.registerModule(simpleModule);
        // 添加内省器（自定义注解功能实现）
        AnnotationIntrospector sis = objectMapper.getSerializationConfig().getAnnotationIntrospector();
        AnnotationIntrospector is1 = AnnotationIntrospectorPair.pair(sis, new ProjectJacksonAnnotationIntrospector());
        objectMapper.setAnnotationIntrospector(is1);

//        objectMapper.setSerializerFactory(
//                objectMapper.getSerializerFactory().withSerializerModifier(new SoarSerializerModifier())
//        );

        return objectMapper;
    }

    /**
     * 序列化
     * @param o
     * @return
     */
    public static String toJson(Object o) {
        try {
            return OBJECT_MAPPER.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 反序列化
     * @param json
     * @param valueType
     * @param <T>
     * @return
     */
    public static <T> T fromJson(String json, Class<T> valueType) {
        try {
            return OBJECT_MAPPER.readValue(json, valueType);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> List<T> fromJsonArray(String json, Class<T> valueType) {
        try {
            CollectionType collectionType = OBJECT_MAPPER
                    .getTypeFactory()
                    .constructCollectionType(ArrayList.class, valueType);
            return OBJECT_MAPPER.readValue(json, collectionType);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 序列化
     * @param o
     * @return
     * @throws JsonProcessingException
     */
    public static String toJsonThrows(Object o) throws JsonProcessingException {
        return OBJECT_MAPPER.writeValueAsString(o);
    }

    /**
     * 反序列化
     * @param json
     * @param valueType
     * @param <T>
     * @return
     * @throws JsonProcessingException
     */
    public static <T> T fromJsonThrows(String json, Class<T> valueType) throws JsonProcessingException {
        return OBJECT_MAPPER.readValue(json, valueType);
    }

}
